마이크로서비스 아키텍처(MSA)에서 트랜잭션 처리 방법

MSA에서는 각 마이크로서비스가 독립적인 데이터베이스를 갖고 있기 때문에, 전통적인 모놀리식 시스템처럼 여러 서비스에 걸쳐 하나의 원자적(ACID) 트랜잭션을 적용할 수 없습니다. 따라서 여러 서비스에 분산된 트랜잭션을 관리하는 것은 매우 중요한 과제입니다. 아래는 면접에서 설명할 때 활용할 수 있는 상세 내용입니다.

MSA에서 분산 트랜잭션이 어려운 이유

MSA에서 트랜잭션을 처리하는 대표 패턴

1. Saga 패턴 (가장 많이 사용되고 권장됨)

개념:

Saga 조율 방식:

사례 예시:

2. 2단계 커밋(Two-Phase Commit, 2PC)

개념:

장점:

단점:

3. 트랜잭셔널 아웃박스(Transactional Outbox) 및 이벤트 기반 처리

면접 요약표

패턴 설명 조율 방식 장점 단점
Saga 로컬 트랜잭션 연속 실행 및 보상 트랜잭션 오케스트레이션 / 코레오그래피 확장성 좋고, 느슨한 결합, 점진적 일관성 보상 트랜잭션 설계 복잡
2단계 커밋 (2PC) 중앙 조정자에 의한 전역 커밋/롤백 결정 중앙 조정자 엄격한 ACID 보장 블로킹, 지연, 확장 어려움
트랜잭셔널 아웃박스 DB 변경과 이벤트 동시 저장 및 비동기 발행 이벤트 기반 느슨한 결합과 비동기 처리 점진적 일관성, 인프라 복잡도

면접에서 이렇게 설명하세요

분산 트랜잭션 관리: 마이크로서비스에서의 SAGA 패턴 설명 (Spring Boot 예제 포함)

간단 요약

마이크로서비스 아키텍처에서는 각 서비스가 독립적인 데이터베이스를 가지므로, 전통적인 ACID(원자성) 트랜잭션을 서비스 간에 적용하기 어렵습니다.
SAGA 패턴은 마이크로서비스에서 분산 트랜잭션을 처리하는 대표적인 방법으로, 로컬 트랜잭션을 순차적으로 실행하고 실패 시 보상 트랜잭션으로 복구하여 데이터 일관성을 유지합니다.

핵심 설명 내용

SAGA 오케스트레이션 작동 방식 (워크플로우 및 다이어그램)

Spring Boot 예제: Saga 오케스트레이터 (오케스트레이션 방식)

1. 주문 서비스

@Service
public class BookingService {
    @Autowired private JmsTemplate jmsTemplate;
    @Autowired private BookingRepository bookingRepository;

    @Transactional
    public void makeBooking(Booking booking) {
        bookingRepository.save(booking); // 로컬 트랜잭션 실행
        jmsTemplate.convertAndSend("bookingQueue", booking); // 오케스트레이터에 이벤트 발행
    }

    @Transactional
    public void confirmBooking(Long bookingId) { /* ... */ }

    @Transactional
    public void cancelBooking(Long bookingId) { /* 보상 트랜잭션 로직 */ }
}

2. 결제 서비스

@Service
public class PaymentService {
    @Autowired private JmsTemplate jmsTemplate;
    @Autowired private PaymentRepository paymentRepository;

    @Transactional
    public void processPayment(Booking booking) {
        Payment payment = new Payment();
        payment.setBookingId(booking.getId());
        // 기타 필드 설정
        paymentRepository.save(payment);
        jmsTemplate.convertAndSend("paymentQueue", payment);
    }

    @Transactional
    public void confirmPayment(Long bookingId) { /* ... */ }

    @Transactional
    public void cancelPayment(Long bookingId) { /* 보상 트랜잭션 로직 */ }
}

3. Saga 오케스트레이터

@Service
public class SagaOrchestrator {
    @Autowired private BookingService bookingService;
    @Autowired private PaymentService paymentService;

    @JmsListener(destination = "bookingQueue")
    public void handleBooking(Booking booking) {
        // 결제 처리 또는 보상 시작
    }

    @JmsListener(destination = "paymentQueue")
    public void handlePayment(Payment payment) {
        try {
            paymentService.confirmPayment(payment.getBookingId());
            bookingService.confirmBooking(payment.getBookingId());
        } catch (Exception e) {
            // 보상 트랜잭션 동작
            bookingService.cancelBooking(payment.getBookingId());
            paymentService.cancelPayment(payment.getBookingId());
        }
    }
}

인터뷰용 일반적 워크플로우

단계 오케스트레이터 행동 성공 시 실패 시
1. 주문 생성 주문 서비스 호출 다음 단계 진행 실패 응답, 보상 없음
2. 결제 결제 서비스 호출 다음 단계 진행 보상: 주문 취소
3. 재고 재고 서비스 호출 주문 완료 보상: 결제 환불, 주문 취소

보상 트랜잭션 예